﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace OpenCube.Nbt
{
	[CLSCompliant(false)]
	public enum NbtTag
		: sbyte
	{
		/// <summary>
		/// Payload: None
		/// Used to mark the end of compound tags. This tag does not have a name, so it is only ever a single byte 0.
		/// </summary>
		End = 00,

		/// <summary>
		/// Payload: 1 byte / 8 bits, signed
		/// A signed integral type. Sometimes used for booleans.
		/// </summary>
		Byte = 01,

		/// <summary>
		/// Payload:  2 bytes / 16 bits, signed, big endian
		/// A signed integral type.
		/// </summary>
		Short = 02,

		/// <summary>
		/// Payload: 4 bytes / 32 bits, signed, big endian
		/// A signed integral type.
		/// </summary>
		Int = 03,

		/// <summary>
		/// Payload: 8 bytes / 64 bits, signed, big endian
		/// A signed integral type.
		/// </summary>
		Long = 04,

		/// <summary>
		/// Payload: 4 bytes / 32 bits, signed, big endian, IEEE 754-2008, binary32
		/// A signed floating point type.
		/// </summary>
		Float = 05,

		/// <summary>
		/// Payload: 8 bytes / 64 bits, signed, big endian, IEEE 754-2008, binary64
		/// A signed floating point type.
		/// </summary>
		Double = 06,

		/// <summary>
		/// Payload: TAG_Int's payload size, then size TAG_Byte's payloads
		/// An array of bytes.
		/// </summary>
		ByteArray = 07,

		/// <summary>
		/// Payload: TAG_Short's payload length, then a UTF-8 string with size length.
		/// A UTF-8 string. It has a size, rather than being null terminated.
		/// </summary>
		String = 08,

		/// <summary>
		/// Payload: TAG_Byte's payload tagId, then TAG_Int's payload size, then size tags' payloads, all of type tagId.
		/// A list of tag payloads, without repeated tag IDs or any tag names.
		/// </summary>
		List = 09,

		/// <summary>
		/// Payload: Fully formed tags, followed by a TAG_End.
		/// A list of fully formed tags, including their IDs, names, and payloads. No two tags may have the same name.
		/// </summary>
		Compound = 10,

		/// <summary>
		/// Payload: TAG_Int's payload size, then size TAG_Int's payloads.
		/// An array of TAG_Int's payloads.
		/// </summary>
		IntArray = 11
	}

	[CLSCompliant(false)]
	public static class NbtTagExtensions
	{
		public static Type GetSystemType(this NbtTag tag)
		{
			Contract.Requires<ArgumentOutOfRangeException>(Enum.IsDefined(typeof(NbtTag), tag));
			Contract.Ensures(Contract.Result<Type>() != null);

			switch (tag)
			{
				case NbtTag.End:
					return typeof(void);
				case NbtTag.Byte:
					return typeof(sbyte);
				case NbtTag.Short:
					return typeof(short);
				case NbtTag.Int:
					return typeof(int);
				case NbtTag.Long:
					return typeof(long);
				case NbtTag.Float:
					return typeof(float);
				case NbtTag.Double:
					return typeof(double);
				case NbtTag.ByteArray:
					return typeof(sbyte[]);
				case NbtTag.String:
					return typeof(string);
				case NbtTag.List:
					return typeof(List<>);
				case NbtTag.Compound:
					return typeof(NbtDictionary);
				case NbtTag.IntArray:
					return typeof(int[]);
			}

			throw new NotImplementedException();
		}
	}
}
